#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sr.h"
#include <cxcore.h>

#define T 20
void ba_liantong(IplImage **);

void threshold(IplImage *src)
{
	printf("*************************\n");
	IplImage *res = cvCreateImage(
			cvGetSize(src),
			IPL_DEPTH_8U,
			1
			);
	unsigned char *data_res = (unsigned char *)res->imageData;
	unsigned char *data_src = (unsigned char *)src->imageData;  
	int step_res = res->widthStep;
	int step_src = src->widthStep;
	int width = src->width;
	int height = src->height;
	int nChannels = src->nChannels;
	int tmp = 0;
	for (int i = 0; i < height; ++ i) {
		for (int j = 0; j < width; ++ j) {
			tmp = 0;
			for (int k = 0; k < nChannels; ++ k) {
				tmp += (int)data_src[i * step_src + j * nChannels + k] / nChannels;
			}
			data_res[i * step_res + j] = (unsigned char )tmp > T ? 55 : 0;
		}
	}
	cvNamedWindow("res");
	cvShowImage("res", res);
	cvWaitKey(0);
	ba_liantong(&res);
	/*
	cvShowImage("rse", res);
	cvWaitKey(0);
	*/

	return;
}

int otsu(const IplImage *src_image) //大津法求阈值
{
	double sum = 0.0;
	double w0 = 0.0;
	double w1 = 0.0;
	double u0_temp = 0.0;
	double u1_temp = 0.0;
	double u0 = 0.0;
	double u1 = 0.0;
	double delta_temp = 0.0;
	double delta_max = 0.0;

	//src_image灰度级
	int pixel_count[256]={0};
	float pixel_pro[256]={0};
	int threshold = 0;
	uchar* data = (uchar*)src_image->imageData;
	//统计每个灰度级中像素的个数
	for(int i = 0; i < src_image->height; i++)
	{
		for(int j = 0;j < src_image->width;j++)
		{
			pixel_count[(int)data[i * src_image->width + j]]++;
			sum += (int)data[i * src_image->width + j];
		}
	}
    cout<<"平均灰度："<<sum / ( src_image->height * src_image->width )<<endl;
	//计算每个灰度级的像素数目占整幅图像的比例
	for(int i = 0; i < 256; i++)
	{
	pixel_pro[i] = (float)pixel_count[i] / ( src_image->height * src_image->width );
	}
	//遍历灰度级[0,255],寻找合适的threshold
	for(int i = 0; i < 256; i++)
	{
		w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0;
		for(int j = 0; j < 256; j++)
		{
			if(j <= i)   //背景部分
			{
				w0 += pixel_pro[j];
				u0_temp += j * pixel_pro[j];
			}
			else   //前景部分
			{
				w1 += pixel_pro[j];
				u1_temp += j * pixel_pro[j];
			}
		}
		u0 = u0_temp / w0;
		u1 = u1_temp / w1;
		delta_temp = (float)(w0 *w1* pow((u0 - u1), 2)) ;
		if(delta_temp > delta_max)
		{
			delta_max = delta_temp;
			threshold = i;
		}
	}
#ifdef DEBUG
	cvNamedWindow("src");
	cvShowImage("src", src_image);
	cvWaitKey(0);
	threshold = 150;
	int width = src_image->width;
	int height = src_image->height;
	int step = src_image->widthStep;
	for (int i = 0; i < height; ++ i) {
		for (int j = 0; j < width; ++ j) {
			data[i * step + j] = (int)data[i * step + j] > threshold ? 0 : 255;
		}
	}
	cvShowImage("src", src_image);
	cvWaitKey(0);
#endif
	return threshold;
}



#define _abs(x) (x) > 0 ? (x) : -(x)
unsigned char *data;
unsigned char *data_tmp;
unsigned char *visited;
int step_src;
int step_tmp;
int width;
int height;

void fenlei(int _x, int _y, int color)
{
	visited[_x * width + _y] = 1;
	int xx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
	int yy[] = {-1, 0, 1, -1, 1, -1, 0, 1};
	int x;
	int y;
	data_tmp[_x * step_tmp + _y] = color;
	for (int k = 0; k < 8; ++ k) {
		x = _x + xx[k];
		y = _y + yy[k];
		if (x < 0 || y < 0 || x > height - 1 || y > width - 1) {
			continue;
		}
		if (data[x * step_src + y] > 40 && !visited[x * width + y]) {
			fenlei(x, y, color);
		}
	}

	return;
}


void liantong(IplImage **src)
{
	assert((*src)->nChannels == 1);
	IplImage *tmp = cvCreateImage(
			cvGetSize(*src),
			IPL_DEPTH_8U,
			1
			);
	width = (*src)->width;
	height = (*src)->height;
	step_src = (*src)->widthStep;
	step_tmp = tmp->widthStep;
	int color = 0;
	data = (unsigned char*) (*src)->imageData;
	data_tmp = (unsigned char *) tmp->imageData; 
	visited = (unsigned char*) malloc (sizeof(unsigned char) * width * height);
	memset(visited, 0, sizeof(unsigned char) * width * height);

	for (int i = 0; i < height; ++ i){
		for (int j = 0; j < width; ++ j) {
			if (!visited[i * width + j] && data[i * step_src + j] > 40) {
				++ color;
				fenlei(i, j, color);
			}
		}
	}
	printf("the sum clolor is : %d\n", color);
	cvReleaseImage(src);

	step_tmp = tmp->widthStep;

	int sum = 0;
	for (int x = 0; x < 255; ++ x) {
		sum = 0;
		for (int i = 0; i < height; ++ i) {
			for  (int j = 0; j < width; ++ j) {
				if (data_tmp[i * step_tmp + j] == x) {
					++ sum;
				}
			}
		}
		if (sum < 50 || sum > 690) { 
			for (int i = 0; i < height; ++ i) {
				for (int j = 0; j < width; ++ j) {
					if (data_tmp[i * step_tmp + j] == x) {
						data_tmp[i * step_tmp + j] = 0;
					}
				}
			}
		}
	}

	for (int i = 0; i < height; ++ i) {
		for (int j = 0; j < width; ++ j) {
			if (data_tmp[i * step_tmp + j] > 0)
			{
				data_tmp[i * step_tmp + j] = 255;
			}
		}
	}
	*src = tmp;

	return;
}

void ba_liantong(IplImage **src)
{
	int width = (*src)->width;
	int height = (*src)->height;
	printf("%d %d\n", width, height);
	int step = (*src)->widthStep;
	unsigned char *data = (unsigned char *) (*src)->imageData;
	unsigned char *biaozhi = (unsigned char *) malloc (sizeof(unsigned char) * width * height);
	memset(biaozhi, 0, sizeof(unsigned char) * width * height);
	unsigned char *zuoshang;
	unsigned char *zuo;
	unsigned char *shang;
	unsigned char *youshang;
	unsigned char *current;
	unsigned char min;
	int flag = 0;
	for (int i = 1; i < height - 1; ++ i) {
		for (int j = 1; j < width - 1; ++ j){
			if (!data[i * step + j]) {
				continue;
			}
			zuo = &biaozhi[i * width + j - 1];
			zuoshang = &biaozhi[(i - 1) * width + j - 1];
			shang = &biaozhi[(i - 1) * width + j];
			youshang = &biaozhi[(i - 1) * width + j + 1];
			current = &biaozhi[i * width + j];
			if      (not (*zuo) && not (*zuoshang) && not (*shang) && not (*youshang)) {
				++ flag;
				*current = flag;
			}
			else if ((*zuo) && (*youshang)) {
				min = *zuo < *youshang ? *zuo : *youshang;
				*current = *youshang = *zuo = min;
			}
			else if ((*zuoshang) && (*youshang)) {
				min = *zuoshang < *youshang ? *zuoshang : *youshang;
				*current = *zuoshang = *youshang = min;
			}
			else {
				if ((*zuo)) {
					*current = *zuo;
					continue;
				}
				if ((*zuoshang)) {
					*current = *zuoshang;
					continue;
				}
				if ((*shang)) {
					*current = *shang;
					continue;
				}
				*current = *youshang;
			}
		}
	}
	printf("the sum flag is %d\n", flag);
	int TH;
	scanf("%d", &TH);
	for (int i = 0; i < height; ++ i) {
		for (int j = 0; j < width; ++ j) {
			if (biaozhi[i * width + j] == TH) {
				data[i * step + j] = 255;
			}
			else {
				data[i * step + j] = 0;
			}
		}
	}
	cvNamedWindow("s");
	cvShowImage("s", *src);
	cvWaitKey(0);

	return;
}


void begin(IplImage *src)
{
	IplImage *dst = cvCreateImage(
			cvSize((src->width << 1) + src->width, (src->height << 1) + src->height ),
			IPL_DEPTH_8U,
			src->nChannels
			);
	int width = src->width;
	int height = src->height;
	int step_src = src->widthStep;
	int step_dst = dst->widthStep;
#ifdef DEBUG
	cvNamedWindow("src");
	cvShowImage("src", src);
	cvWaitKey(0);
#endif
	cvResize(src, dst, CV_INTER_CUBIC);
#ifdef DEBUG
	cvNamedWindow("dst");
	cvShowImage("dst", dst);
	cvWaitKey(0);
#endif

	return;
}


const int MAX_CORNERS = 500;

void king_lk()
{
	IplImage *imgA = cvLoadImage("res/result/1.png", CV_LOAD_IMAGE_GRAYSCALE);
	IplImage *imgB = cvLoadImage("res/result/2.png", CV_LOAD_IMAGE_GRAYSCALE);
	IplImage *imgC = cvLoadImage("res/result/1.png", CV_LOAD_IMAGE_GRAYSCALE);

	CvSize img_sz = cvGetSize(imgA);
	int win_size = 10;

	IplImage *eig_image = cvCreateImage(img_sz, IPL_DEPTH_32F, 1);
	IplImage *tmp_image = cvCreateImage(img_sz, IPL_DEPTH_32F, 1);

	int corner_count = MAX_CORNERS;
	CvPoint2D32f *cornersA = new CvPoint2D32f[MAX_CORNERS];
	
	cvGoodFeaturesToTrack(
			imgA,
			eig_image,
			tmp_image,
			cornersA,
			&corner_count,
			0.01,
			5.0,
			0,
			3,
			0,
			0.04
			);

	cvFindCornerSubPix(
			imgA,
			cornersA,
			corner_count,
			cvSize(win_size, win_size),
			cvSize(-1, -1),
			cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 20, 0.03)
			);

	char features_found[MAX_CORNERS];
	float feature_errors[MAX_CORNERS];

	CvSize pyr_sz = cvSize(imgA->width + 8, imgB->height / 3);
	IplImage *pyrA = cvCreateImage(pyr_sz, IPL_DEPTH_32F, 1);
	IplImage *pyrB = cvCreateImage(pyr_sz, IPL_DEPTH_32F, 1);
	
	CvPoint2D32f *cornersB = new CvPoint2D32f[MAX_CORNERS];

	cvCalcOpticalFlowPyrLK(
			imgA,
			imgB,
			pyrA,
			pyrB,
			cornersA,
			cornersB,
			corner_count,
			cvSize(win_size, win_size),
			5,
			features_found,
			feature_errors,
			cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, .3),
			0
			);

	for (int i = 0; i < corner_count; ++ i) {
		if (features_found[i] == 0 || feature_errors[i] > 550) {
			printf("error is %s\n", feature_errors[i]);
			continue;
		}
		printf("Got it\n");
		CvPoint p0 = cvPoint(
				cvRound(cornersA[i].x),
				cvRound(cornersB[i].y)
				);

		CvPoint p1 = cvPoint(
				cvRound(cornersB[i].x),
				cvRound(cornersB[i].y)
				);
		cvLine(imgC, p0, p1, CV_RGB(255, 0, 0), 2);
	}
	cvNamedWindow("ImageA", 0);
	cvNamedWindow("ImageB", 0);
	cvNamedWindow("dst", 0);
	cvShowImage("ImageA", imgA);
	cvShowImage("ImageB", imgB);
	cvShowImage("dst", imgC);

	cvWaitKey(0);

	return;
}

void iter(IplImage *src, IplImage *dst, IplImage *result)
{
#ifdef DEBUG
	cvNamedWindow("src");
	cvNamedWindow("dst");
	cvNamedWindow("result");
	cvShowImage("src", src);
	cvShowImage("dst", dst);
	cvShowImage("result", result);
	cvWaitKey(0);
#endif


#ifdef DEBUG
	cvDestroyAllWindows();
#endif
	return ;
}

